

<template>
  <WebGLCanvas :id="id"/>
</template>

<script setup lang="ts">
  import { useCreateProgram } from "~/composables"
  import { vertexShaderSource, fragmentShaderSource } from "~/composables/webgl/webgl-fundamentals"

  const id = 'webgl-fundamentals'

  useHead({
    title: 'WebGL 基础概念'
  })

  onMounted(() => {
    const gl = useCanvas({
      id: 'webgl-fundamentals'
    })
    // 清屏
    useCanvasClear(gl)

    // 1. 创建顶点着色器、片元着色器
    const vertexShader = useCreateShader(gl, gl.VERTEX_SHADER, vertexShaderSource)
    const fragmentShader = useCreateShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource)
    if (!vertexShader || !fragmentShader) {
      return
    }
    // 2. 现在我们已经在GPU上创建了一个GLSL着色程序，
    // 我们还需要给它提供数据。 
    // WebGL的主要任务就是设置好状态并为GLSL着色程序提供数据
    const program = useCreateProgram(gl, vertexShader, fragmentShader)
    if (!program) {
      return
    }
    // 从刚才创建的GLSL着色程序中找到这个属性值所在的位置以及颜色
    const positionAttributeLocation = gl.getAttribLocation(program, 'a_position')
    const colorUniformLocation = gl.getUniformLocation(program, 'u_color')
    // 属性值从缓冲中获取数据，所以我们创建一个缓冲
    const positionBuffer = gl.createBuffer()
    // 绑定位置信息缓冲
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)

    // 通过绑定点向缓冲中存放数据
    // const positions = [
    //   0, 0,
    //   0, 0.5,
    //   0.7, 0,
    //   0, 0.5,
    //   0.7, 0.5,
    //   0.7, 0
    // ]
    // WebGL需要强类型数据 所以使用`Float32Array`
    // `bufferData`作用 复制这些数据到GPU的`positionBuffer`对象上
    // `STATIC_DRAW` 提示WebGL我们不会经常改变这些数据
    // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)

    // 告诉它用我们之前写好的着色程序（一个着色器对）
    gl.useProgram(program)

    // 告诉WebGL怎么从我们之前准备的缓冲中获取数据给着色器中的属性。 
    // 首先我们需要启用对应属性
    gl.enableVertexAttribArray(positionAttributeLocation)

    // 指定从缓冲中读取数据的方式
    // 告诉属性怎么从positionBuffer中读取数据 (ARRAY_BUFFER)
    const size = 2            // 每次迭代运行提取两个单位数据
    const type = gl.FLOAT     // 每个单位的数据类型是32位浮点型
    const normalize = false   // 不需要归一化数据
    const stride = 0          //  0 = 移动单位数量 * 每个单位占用内存（sizeof(type)）
                              // 每次迭代运行运动多少内存到下一个数据开始点
    const offset = 0          // 从缓冲起始位置开始读取
    gl.vertexAttribPointer(
      positionAttributeLocation,
      size,
      type,
      normalize,
      stride,
      offset
    )

    // 排列生成50个矩形 10 * 5
    // 方式一
    // const rectangleWidth = (window.innerWidth / 10)
    // const rectangleHeight = (window.innerHeight / 5)
    // console.info(rectangleWidth, rectangleHeight)
    // // 像素坐标转成裁剪坐标
    // const pixel2ClipX = (x: number) => {
    //   return (x / window.innerWidth) * 2 - 1
    // }
    // const pixel2ClipY = (y: number) => {
    //   // WebGL 左下角(0，0) 需要翻转 y轴
    //   return ((y / window.innerHeight) * 2 - 1) * -1
    // }
    // for (let m = 0; m < 10; m++) {
    //   for (let n = 0; n < 5; n++) {
    //     // 4个点 ABCD
    //     const A = [m * rectangleWidth, n * rectangleHeight]
    //     const B = [(m + 1) * rectangleWidth, n * rectangleHeight]
    //     const C = [(m + 1) * rectangleWidth, (n + 1) * rectangleHeight]
    //     const D = [m * rectangleWidth, (n + 1) * rectangleHeight]
    //     // 2个三角形 ABC ADC
    //     const rectanglePositions = [
    //       pixel2ClipX(A[0]), pixel2ClipY(A[1]),
    //       pixel2ClipX(B[0]), pixel2ClipY(B[1]),
    //       pixel2ClipX(C[0]), pixel2ClipY(C[1]),
    //       pixel2ClipX(A[0]), pixel2ClipY(A[1]),
    //       pixel2ClipX(D[0]), pixel2ClipY(D[1]),
    //       pixel2ClipX(C[0]), pixel2ClipY(C[1]),
    //     ]
    //     console.info(rectanglePositions)
    //     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    //       pixel2ClipX(A[0]), pixel2ClipY(A[1]),
    //       pixel2ClipX(B[0]), pixel2ClipY(B[1]),
    //       pixel2ClipX(C[0]), pixel2ClipY(C[1]),
    //       pixel2ClipX(A[0]), pixel2ClipY(A[1]),
    //       pixel2ClipX(D[0]), pixel2ClipY(D[1]),
    //       pixel2ClipX(C[0]), pixel2ClipY(C[1]),
    //     ]), gl.STATIC_DRAW)
    //     // 设置随机颜色
    //     gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1)
    //     // 绘制矩形
    //     gl.drawArrays(gl.TRIANGLES, 0, 6)
    //   }
    // }

    // 方式二
    for (let m = 0; m < 10; m++) {
      for (let n = 0; n < 5; n++) {
        // ABCD个点 ABC ADC
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          m*0.2 - 1, 1 - n*0.4, // A
          (m+1)*0.2 - 1, 1 - n*0.4, // B
          (m+1)*0.2 - 1, 1- (n+1)*0.4, // C
          m*0.2 - 1, 1 - n*0.4, // A
          m*0.2 - 1, 1 - (n+1)*0.4, // D
          (m+1)*0.2 - 1, 1- (n+1)*0.4, // C
        ]), gl.STATIC_DRAW)
        // 设置随机颜色
        gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1)
        // 绘制矩形
        gl.drawArrays(gl.TRIANGLES, 0, 6)
      }
    }

    // 让WebGL运行我们的GLSL着色程序
    // gl.drawArrays(gl.TRIANGLES, 0, 6)
  })
  
</script>
